﻿#region Using Directives

    using System;
    using System.Collections.Generic;
    using System.Data.Linq;
    using System.Linq;
    using System.Text;
    //using System.Transactions;
    using System.Xml.Linq;

    using Csla;
    using Csla.Data;
    using Csla.Reflection;
    using Csla.Server;

    using MarketPulse.BusinessLogic.Private;
    using MarketPulse.BusinessLogic.Private.Criteria;

    using MarketPulse.DataAccess.DataContextObjects.Production;

#endregion

namespace MarketPulse.DataAccess.Factory
{
    /// <summary>
    /// Abstracts the data access for a BusinessLogic.Private.Survey away from a BusinessLogic.Private.Survey Business Object.
    /// </summary>
    public class SurveyFactory : ObjectFactory
    {

        #region Member Variables

            /// <summary>
            /// Property that stores the name of the class.
            /// </summary>
            private static readonly Type mClass = System.Reflection.MethodBase.GetCurrentMethod().DeclaringType;

            /// <summary>
            /// Property that stores the log4net logger for this class.
            /// </summary>
            private static readonly log4net.ILog mLog = log4net.LogManager.GetLogger(mClass);

        #endregion

        #region Methods

            #region Create Nethods

                /// <summary>
                /// Creates a new Survey and returns the new Survey object.
                /// </summary>
                /// <returns>The newly created survey</returns>
                public BusinessLogic.Private.Survey Create()
                {
                    var survey = (BusinessLogic.Private.Survey)MethodCaller.CreateInstance(typeof(BusinessLogic.Private.Survey));

                    survey.Obsolete = false;

                    MarkNew(survey);

                    return survey;
                }

            #endregion

            #region Fetch Methods

                #region Survey

                    /// <summary>
                    /// Fetches an existing Survey from the database given a guid *and* a versionId
                    /// </summary>
                    /// <param name="id">The Guid of the survey</param>
                    /// <param name="id">The versionId of the survey</param>
                    /// <returns>The survey object fetched from the database</returns>
                    public BusinessLogic.Private.Survey Fetch(UniqueSurveyCriteria criteria)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                var survey = (BusinessLogic.Private.Survey)MethodCaller.CreateInstance(typeof(BusinessLogic.Private.Survey));

                                var selectResult = manager.DataContext.UspSurveySelect(criteria.Guid, criteria.VersionID);
                                
                                // Get the result
                                UspSurveySelectResult result = null;
                                try
                                {
                                    result = selectResult.Single();
                                }
                                catch (InvalidOperationException ioe)
                                {
                                    // Construct error message
                                    StringBuilder errorMessage = new StringBuilder();
                                    errorMessage.Append("Unable to locate exactly one Survey with Guid = [ ");
                                    errorMessage.Append(criteria.Guid);
                                    errorMessage.Append(" ] and versionID = [ ");
                                    errorMessage.Append(criteria.VersionID);
                                    errorMessage.Append(" ]");
                                    mLog.Error(errorMessage.ToString(), ioe);
                                    throw new DataAccessException(errorMessage.ToString());
                                }
                                LoadProperties(survey, result);
                                return survey;
                            }
                        }
                        catch (DataAccessException dae)
                        {
                            mLog.Error(dae.ToString());
                            throw dae;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                    /// <summary>
                    /// Method that fetches an existing Survey from the database given a guid. 
                    /// It retrieves the latest survey, i.e. one where the current DateTime is
                    /// larger than effective start date and yet smaller than EffectiveEndDate 
                    /// and with the highest versionID.
                    /// </summary>
                    /// <param name="id">The Guid of the survey</param>
                    /// <param name="id">The versionID of the survey</param>
                    /// <returns>The survey object fetched from the database</returns>
                    public BusinessLogic.Private.Survey Fetch(Guid guid)
                    {
                        try
                        {
                            using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                            {
                                var survey = (BusinessLogic.Private.Survey)MethodCaller.CreateInstance(typeof(BusinessLogic.Private.Survey));

                                var selectResult = manager.DataContext.UspSurveySelect(guid, null);
                               
                                // Get the result
                                UspSurveySelectResult result = null;
                                try
                                {
                                    result = selectResult.Single();
                                }
                                catch (InvalidOperationException ioe)
                                {
                                    // Construct error message
                                    StringBuilder errorMessage = new StringBuilder();
                                    errorMessage.Append("Unable to locate exactly one Survey with Guid = [ ");
                                    errorMessage.Append(guid);
                                    errorMessage.Append(" ]");
                                    mLog.Error(errorMessage.ToString(), ioe);
                                    throw new DataAccessException(errorMessage.ToString());
                                }
                                LoadProperties(survey, result);
                                return survey;                                
                            }
                        }
                        catch (DataAccessException dae)
                        {
                            mLog.Error(dae.ToString());
                            throw dae;
                        }
                        catch (Exception ex)
                        {
                            mLog.Error(ex.ToString());
                            throw ex;
                        }
                    }

                #endregion

            #endregion

            #region Update Methods

                    /// <summary>
                    /// Persists an altered BusinessLogic.Private.Survey object in the database.
                    /// </summary>
                    /// <param name="survey">The survey object to persist.</param>
                    /// <returns>The BusinessLogic.Private.Survey object potentially altered by the act of persisting it.</returns>
                    [Transactional(TransactionalTypes.TransactionScope)]
                    public BusinessLogic.Private.Survey Update(BusinessLogic.Private.Survey survey)
                    {
                        using (var manager = ContextManager<MUM_dev>.GetManager(Database.BusinessSystem))
                        {
                            // This is the development UserID  TODO: Obtained the authenticated userId
                            // from the Csla context
                            survey.InsertUserGUID = new Guid("590982D5-857A-4CCB-80CC-BBC3D152EC88");
                            if (survey.IsNew || survey.IsXmlDirty)
                            {

                                Nullable<Guid> id = survey.GUID;
                                // force the survey Id to null to indicate to the stored procedure
                                // that it should generate one instead of attempting an insert
                                // with what must be a pre-existing one (for an IsOld object)
                                Nullable<long> versionId = null;
                                Nullable<DateTime> insertDateTime = new Nullable<DateTime>();
                                // Persist the new BusinessLogic.Private.Survey in the database.
                                // The stored procedure should increment the versionId
                                // as we have only supplied a Guid 
                                manager.DataContext.UspSurveyInsert(ref id, ref versionId,
                                                                survey.SurveyLabel, survey.SurveyXML,
                                                                survey.EffectiveStartDateTime,
                                                                survey.EffectiveEndDateTime,
                                                                survey.Obsolete,
                                                                survey.InsertUserGUID, ref insertDateTime);

                                if (survey.IsNew)
                                {
                                    LoadProperty(survey, BusinessLogic.Private.Survey.GUIDProperty, id);
                                }
                                LoadProperty(survey, BusinessLogic.Private.Survey.mVersionIdProperty, versionId.Value);

                                if (insertDateTime.HasValue)
                                {
                                    survey.InsertDateTime = insertDateTime.Value.ToString();
                                    survey.UpdateDateTime = survey.InsertDateTime;
                                }
                            }
                            else if (survey.IsDirty)
                            {
                                manager.DataContext.UspSurveyUpdate(survey.GUID, survey.VersionID, survey.SurveyLabel, survey.SurveyXML, survey.EffectiveStartDateTime, survey.EffectiveEndDateTime, survey.Obsolete, survey.UpdateUserGUID);
                            }
                            return survey;
                        }
                    }

            #endregion

            #region Local Methods

                /// <summary>
                /// 
                /// </summary>
                /// <param name="target"></param>
                /// <param name="source"></param>
                protected void LoadProperties(BusinessLogic.Private.Survey target, UspSurveySelectResult source)
                {
                    // inherited from MarketPulseBase<BusinessLogic.Private.Survey>
                    LoadProperty(target, BusinessLogic.Private.Survey.GUIDProperty, source.SurveyGUID);
                    LoadProperty(target, BusinessLogic.Private.Survey.ObsoleteProperty, source.Obsolete.Value);
                    LoadProperty(target, BusinessLogic.Private.Survey.InsertUserGUIDProperty, source.InsertUserGUID.Value);
                    LoadProperty(target, BusinessLogic.Private.Survey.InsertDateTimeProperty, (SmartDate)source.InsertDateTime);
                    LoadProperty(target, BusinessLogic.Private.Survey.UpdateUserGUIDProperty, source.UpdateUserGUID.Value);
                    LoadProperty(target, BusinessLogic.Private.Survey.UpdateDateTimeProperty, (SmartDate)source.UpdateDateTime);
                    // others
                    LoadProperty(target, BusinessLogic.Private.Survey.mVersionIdProperty, source.SurveyVersionID.Value);
                    LoadProperty(target, BusinessLogic.Private.Survey.mSurveyLabelProperty, source.SurveyLabel);
                    LoadProperty(target, BusinessLogic.Private.Survey.mSurveyXMLProperty, source.SurveyXML.ToString());
                    LoadProperty(target, BusinessLogic.Private.Survey.mEffectiveStartDateTimeProperty, source.EffectiveStartDateTime);
                    LoadProperty(target, BusinessLogic.Private.Survey.mEffectiveEndDateTimeProperty, source.EffectiveEndDateTime);
                }

            #endregion

        #endregion
    }
}
